import time

from fastapi import FastAPI, Cookie
from typing import Optional
import uvicorn
from lxml import etree
import requests, lib, re
from pydantic import BaseModel
import datetime
from fastapi.encoders import jsonable_encoder


class UpScore(BaseModel):
    id: str = None
    up_time: int = None
    targetTime: datetime.datetime


class UpNotify(BaseModel):
    id: str = None
    content: str = None
    title: str = None


class MailContent(BaseModel):
    study_id: str = None
    content: str = None


class UpInfo(BaseModel):
    password: str = None
    address: str = None
    now_address: str = None
    contact: str = None
    phone: str = None
    province_id: str = None
    city_id: str = None
    study_id: str = None


class AllField(BaseModel):
    school_id: str = ''
    password: str = ''
    email: str = ''
    name: str = ''
    sex: str = ''
    study_id: str = ''
    college_id: str = ''
    address: str = ''
    contact: str = ''
    phone: str = ''
    province_id: str = ''
    city_id: str = ''
    now_address: str = ''
    addTime: datetime.date = datetime.date.today()
    expireTime: datetime.date = datetime.date.today() + datetime.timedelta(days=15)


class UpActive(BaseModel):
    school_id: str = ''
    active: bool = True


class NewScore(BaseModel):
    pay_no: str = ''


app = FastAPI()


def get_data(PHPSESSID=''):
    sess = requests.session()
    sess.cookies.set('PHPSESSID', PHPSESSID)
    res = sess.get('http://bcfl.sdufe.edu.cn/student/handle_ext.html')
    doms = etree.HTML(res.text)
    qd_field = lib.data_field
    fin = {}
    for field in qd_field:
        if field == 'sex':
            fin[field] = doms.xpath('//*[@name="sex" and @checked]/@value')[0]
        elif field == 'college_id':
            fin[field] = doms.xpath('//*[@name="college_id"]//*[@selected]/@value')[0]
        elif field == 'province_id':
            fin[field] = doms.xpath('//*[@name="province_id"]//*[@selected]/@value')[0]
        elif field == 'city_id':
            fin[field] = ''
        else:
            fin[field] = doms.xpath('//*[@id="{}"]/@value'.format(field))[0]
    return fin


@app.post("/new_score")
async def new_score(item: NewScore):
    drive = lib.SQL()
    data = drive.select(['*'], 'codepay_order', 'pay_no=' + item.pay_no)[0]
    fin = {
        'study_id': data[1],
        'price': data[2],
    }
    if data[9] != 2:
        return -1
    s = max(drive.select(['expireTime'], 'userprofile', "study_id=%s" % fin['study_id'])[0][0], datetime.date.today())
    sql = "update userprofile SET expireTime = \'%s\' where study_id = \'%s\'" % (s + datetime.timedelta(
        days=int(float(fin['price']) * 10)), fin['study_id'])
    try:
        drive.run(sql)
        drive.db.commit()
        sql = "update codepay_order SET status=1 where pay_no=\'%s\''" % item.pay_no
        drive.run(sql)
        drive.db.commit()
        return 1
    except:
        return 0


@app.get("/index")
async def root(PHPSESSID: Optional[str] = Cookie(None)):
    data = get_data(PHPSESSID)
    drive = lib.SQL()
    fin = drive.select(['*'], 'userprofile', "study_id='%s'" % data['study_id'])
    return {
        'data': data,
        'exist': len(fin) != 0
    }


@app.get("/user/info")
async def get_info(id: str):
    drive = lib.SQL()
    s = drive.select(lib.field_name, 'UserProfile', check_field='study_id = ' + id)[0]
    fin = {}
    for index, item in enumerate(s):
        fin[lib.field_name[index]] = item
    fin['addTime'] = fin['addTime'].strftime('%Y-%m-%d')
    return fin


@app.get("/sign/status")
async def check_sign(PHPSESSID: Optional[str] = Cookie(None)):
    sess = requests.session()
    sess.cookies.set('PHPSESSID', PHPSESSID)
    res = sess.get('http://bcfl.sdufe.edu.cn/Student/handle_person')
    contents = res.text
    pattern = 'stateDate.*?;'
    reg = re.compile(pattern)
    stateDate = re.findall(reg, contents)[0]
    items = eval(stateDate.replace('stateDate', '').replace(';', '').replace('=', ''))
    fin = {}
    for item in items:
        fin[item['date']] = item['state']
    return fin


@app.post("/update/score")
async def up_score(data: UpScore):
    drive = lib.SQL()
    s = max(drive.select(['expireTime'], 'userprofile', "study_id=%s" % data.id)[0][0], datetime.date.today())
    if abs((data.targetTime.date() - (s + datetime.timedelta(days=data.up_time * 30))).days) > 5:
        return True
    sql = "update userprofile SET expireTime = \'%s\' where study_id = \'%s\'" % (s + datetime.timedelta(
        days=data.up_time * 30), data.id)
    try:
        drive.run(sql)
        drive.db.commit()
        return True
    except:
        return False


@app.post("/save/info")
async def save_info(data: UpInfo):
    try:
        drive = lib.SQL()
        sql = "update userprofile set password=\'%s\',address=\'%s\',now_address=\'%s\',contact=\'%s\',phone=\'%s\',province_id=%s,city_id=%s where " \
              "study_id=\'%s\'" % (data.password,
                                   data.address, data.now_address, data.contact, data.phone, data.province_id,
                                   data.city_id,
                                   data.study_id)
        drive.run(sql)
        drive.db.commit()
        return True
    except:
        return False


@app.post("/up/active")
async def up_active(data: UpActive):
    try:
        drive = lib.SQL()
        sql = "update userprofile set active = %s where school_id=\'%s\'" % (data.active, data.school_id)
        drive.run(sql)
        drive.db.commit()
        return 0 if data.active else 1
    except:
        return -1


@app.get("/del/info")
async def save_info(id: int):
    try:
        drive = lib.SQL()
        sql = "delete from userprofile where school_id=\'%s\'" % id
        drive.run(sql)
        drive.db.commit()
        return True
    except:
        return False


@app.post("/insert/info")
async def insert_info(info: AllField):
    drive = lib.SQL()
    info = jsonable_encoder(info)
    info['addTime'] = str(datetime.datetime.now())
    info['expireTime'] = str(datetime.date.today() + datetime.timedelta(days=3))
    values = []
    fields = lib.field_name[:-1]
    for item in fields:
        values.append("\'" + info[item] + "\'")
    values = ','.join(values)
    fields = ','.join(fields)
    sql = "insert into userprofile (%s) values (%s)" % (fields, values)
    drive.run(sql)
    drive.db.commit()
    return True


@app.get("/getScore")
async def get_score():
    res = requests.post('http://upload.chaojiying.net/Upload/GetScore.php', data={
        'user': 'DMSintalor',
        'pass': 'LzC200138'
    }).json()
    return {'tifen': res['tifen']}


@app.get("/get_city")
async def get_city(province_id: str):
    res = requests.post(url='http://bcfl.sdufe.edu.cn/Portal/Area/handle_ajax_city/', data={
        'province_id': province_id
    })
    return res.text


@app.post("/admin/user")
async def all_user():
    drive = lib.SQL()
    fields = lib.field_name
    data_list = drive.select(fields, 'userprofile')
    fin = []
    for data in data_list:
        f = {}
        for i, field in enumerate(fields):
            f[field] = data[i]
            if field == 'city_id':
                f['city'] = lib.provinces[str(f['province_id'])]['city'][str(data[i])]
                f['province'] = lib.provinces[str(f['province_id'])]['name']
        f['addTime'] = f['addTime'].strftime('%Y-%m-%d %H:%M')
        fin.append(f)
    return fin


@app.get("/notify")
async def notify(n_id: str = ''):
    drive = lib.SQL()
    if n_id == 'all':
        sql = "select * from notify order by addTime desc"
        drive.run(sql)
        items = drive.cursor.fetchall()
        fin = []
        for item in items:
            s = {'content': item[2], 'addTime': item[3].strftime('%m-%d %H:%M'), 'title': item[1], 'id': item[0]}
            fin.append(s)
        return fin
    elif n_id == 'latest':
        sql = "select * from notify order by addTime desc limit 1"
        drive.run(sql)
        item = drive.cursor.fetchall()[0]
        fin = {'id': item[0], 'title': item[1], 'content': item[2], 'addTime': item[3].strftime('%m-%d %H:%M')}
        return fin
    else:
        items = drive.select(['content', 'addTime', 'title'], 'notify', "id=\'%s\'" % n_id)[0]
        fin = {'title': items[2], 'content': items[0], 'addTime': items[1].strftime('%m-%d %H:%M')}
        return fin


@app.post('/update/notify')
async def up_notify(item: UpNotify):
    drive = lib.SQL()
    sql = "update notify set content = \'%s\' where id=\'%s\'" % (item.content, item.id)
    drive.run(sql)
    drive.db.commit()


@app.post('/insert/notify')
async def in_notify(item: UpNotify):
    drive = lib.SQL()
    sql = "insert into notify (content,title) values (\'%s\',\'%s\')" % (item.content, item.title)
    drive.run(sql)
    drive.db.commit()


@app.post('/sendmail')
async def sendmail(item: MailContent):
    url = 'https://formspree.io/f/mzbyybpa'
    res = requests.post(url, data={'study_id': item.study_id, 'content': item.content})
    return res.status_code


@app.get('/user/count')
async def user_count():
    drive = lib.SQL()
    dataset = drive.select(['*'], 'userprofile')
    return len(dataset)


if __name__ == '__main__':
    uvicorn.run("main:app", port=8000)
